﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace DefensiveShield
{
    public static partial class OS
    {
        //---------------------------------------------------------------------------------------------------------------------------------
        //---------------------------------------------------------------------------------------------------- SAVE SECRET FILE -----------
        //---------------------------------------------------------------------------------------------------------------------------------
        /**
            @brief Функция сохранения текста в секретный файл
            @param minimalSecrecy - уровень секретности текущей сессии пользователя
             * 
             * Данная функция шифрует переданный ей текст и записывает в указанный файл, ключ шифрования генерируется на ходу при каждом сохранении. При этом ключ должен быть зашифрован на глобальном ключе и записан в FilePassport.
             * 
             * Проверяется, есть ли у пользователя доступ к файлу, в соответствии с дискреционной и мандатной моделью разграничения доступа.
             * 
             * Если гриф, переданный в качестве параметра выше, чем тот, что был у файла раньше, то его необходимо повысить
             * 
             * В случае, если файл не существует, он создаётся и регистрируется, с переносом соответствующих атрибутов пользователя, при этом файл имеет расширение DefensiveShield.Properties.Resources.SecretFileExtention
             * 
            @return код ошибки, при её наличии
        */
        public static ErrorCodes SaveSecretFile(OsSession session, string fileName, string text)
        {
            try
            {
                // Дискреционный контроль доступа
                var rights = GetDiscretionalAccessPermission(session, fileName);
                if (rights < Rights.ReadWrite) // У пользователя нет доступа к файлу на запись
                {
                    LogMessage(session.UserName, "Not enough discretional access to save file", fileName);
                    return ErrorCodes.FileNotWritable;
                }
                // Мандатный контроль доступа
                var mandatoryAccessCode = CheckMandatoryAccessPermission(session, fileName);
                if (mandatoryAccessCode != ErrorCodes.NoError) // Допуск пользователя не ниже грифа файла
                {
                    LogMessage(session.UserName, "Not enough mandatory access to save file", fileName);
                    return mandatoryAccessCode;
                }
                var newFile = !File.Exists(fileName);
                if (Files.ContainsKey(fileName))
                {
                    // Повышение грифа файла, если допуск сессии выше
                    if (session.SessionSecrecy.CompareTo(Files[fileName].SecrecyNum) > 0)
                        Files[fileName].SecrecyNum = session.SessionSecrecy;
                }
                else
                {
                    //File.Delete(fileName);
                    fileName = fileName.Remove(fileName.LastIndexOf('.')) + DefensiveShield.Properties.Resources.SecretFileExtention;
                    if (!File.Exists(fileName)) { var stream = File.Create(fileName); stream.Close(); }
                    var registerFileCode = RegisterFileSystemObject(session, fileName);
                    if (registerFileCode != ErrorCodes.NoError) { return registerFileCode; }
                }

                var key = GenerateKey();  
                // Зашифрование текста
                var encryptedText = Encrypt(text, key);
                // запись текста в файл
                
                //var fileWriter = new StreamWriter(fileName);
                //fileWriter.Write(encryptedText);
                File.WriteAllBytes(fileName, Convert.FromBase64String(encryptedText));
                //fileWriter.Close();
                Files[fileName].Key = Encrypt(key, GlobalKey);
                LogMessage(session.UserName, newFile ? "Created secret file" : "Saved secret file", fileName);
                return ErrorCodes.NoError;
            }
            catch (Exception e)
            {
                LogMessage(session.UserName, "Failed to save secret file: " + e.Message, fileName);
                return ErrorCodes.UnknownError;
            }
        }

        //---------------------------------------------------------------------------------------------------------------------------------
        //---------------------------------------------------------------------------------------------------- SAVE SECRET FILE -----------
        //---------------------------------------------------------------------------------------------------------------------------------
        /**
            @brief Функция открытия секретного файла
             * 
             * Данная функция открывает файл. Если файл не был зарегистрирован в системе, то он открывается как просто не зашифрвоанный текстовый файл, и его содержимое возвращается.
             * Если файл был зарегистрирован в системе, значит он шифрованный, и его нужно расшифровать на ключе, который лежит в структуре о файле, и который сам зашифрован на глоблаьном ключе системы
             * 
             * Проверяется, есть ли у пользователя доступ к файлу, в соответствии с дискреционной и мандатной моделью разграничения доступа.
             * 
            @return string - расшифрованное содержимое файла
            @return null - в случае ошибки
        */

        public static string OpenSecretFile(OsSession session, string fileName)
        {
            try
            {
                string text;
                if (!Files.ContainsKey(fileName))
                {
                    var fileReader = new StreamReader(fileName, Encoding.Default);
                    text = fileReader.ReadToEnd(); // Считываем файл в строку
                    fileReader.Close();
                    return text;
                }
                var rights = GetDiscretionalAccessPermission(session, fileName);
                if (rights < Rights.Read) // У пользователя нет доступа к файлу на чтение
                {
                    LogMessage(session.UserName, "Not enough discretional access to read file", fileName);
                    return null;
                }
                // Мандатный контроль доступа
                var mandatoryAccessCode = CheckMandatoryAccessPermission(session, fileName);
                if (mandatoryAccessCode != ErrorCodes.NoError) // Допуск пользователя не ниже грифа файла
                {
                    LogMessage(session.UserName, "Not enough mandatory access to read file", fileName);
                    return null;
                }

                //var fileReader = new StreamReader(fileName, Encoding.Default);
                //text = fileReader.ReadToEnd(); // Считываем файл в строку
                var textBytes = File.ReadAllBytes(fileName);
                //fileReader.Close();
                if (!Files.ContainsKey(fileName)) // Проверяем, зарегистрирован файл или нет
                {
                    LogMessage(session.UserName, "Nonsecret file contents obtained successfully", fileName);
                    var byteConverter = new UnicodeEncoding();
                    return byteConverter.GetString(textBytes); // Файл не зарегистрирован, возвращаем содержимое
                }
                else
                {
                    LogMessage(session.UserName, "Secret file contents obtained successfully", fileName);
                    text = Convert.ToBase64String(textBytes); // Считываем файл в строку
                    var decryptedText = Decrypt(text, Decrypt(Files[fileName].Key, GlobalKey));
                    return decryptedText; // Файл зарегистрирован, возвращаем расшифрованное содержимое
                }
            }
            catch (Exception e)
            {
                LogMessage(session.UserName, "Failed to obtain file contents: " + e.Message, fileName);
                return null;
            }
        }
    }
}
